﻿//#define _CRT_SECURE_NO_WARNINGS
//#include <stdio.h>
//#include <stdlib.h>
//#include <ctype.h>

#include "common.h"

int up_stairs_all(int n)
{ // 每次可以走 1 步或 2 步，计算 n 阶楼梯所有可能的走法
	//if (n <= 1)
	//	return 1; // 1 阶楼梯只有一种走法
	//else if (n <= 2)
	//	return 2; // 2 阶楼梯有两种走法
	if (n <= 2)
		return n;
	else
		return up_stairs_all(n - 1) + up_stairs_all(n - 2);
}

int* create_array(static int arr[], int size)
{ // 创建一个 size 大小的数组并返回数组指针
	arr = (int*)malloc(size * sizeof(int));
	if (arr == NULL) // 内存分配失败
		return NULL;
	//exit(-1); // 退出程序，返回 -1，头文件为 stdlib.h
	return arr;
}

int pop_num(int* arr, int* size, int value)
{ // 在数组 arr 中前 size 个元素中搜索 value 并返回其指针，若不存在返回 NULL
	// 删除值之后，数组元素的顺序不变
	int i;
	int j = 0;
	for (i = 0; i < *size; i++)
	{
		/* if (arr[i] != value)
			arr[j++] = arr[i]; // 复制值到数组的前面 */
		if (arr[i] == value)
		{
			int del_num = arr[i]; // 记录要删除的值
			for (j = i; j < *size - 1; j++)
				arr[j] = arr[j + 1];
			arr[*size - 1] = 0; // 最后一个元素置 0
			*size -= 1;
			return del_num;
		}
	}
	return -1; // 未找到 value
}

void show_pop_after_array()
{ // 自己输入一个整型数组，删除一个查找值，打印删除后数组（不改变顺序）的函数
	int n;
	printf("请输入数组大小：");
	int n_input = scanf("%d", &n);
	int* arr = create_array(NULL, n);
	int i;
	printf("请输入%d个数组元素(用空格分隔)：\n", n);
	for (i = 0; i < n; ++i)
	{
		int i_input = scanf("%d", &arr[i]);
	}
	int value;
	printf("请输入要删除的元素：");
	int value_input = scanf("%d", &value);
	int del_num = pop_num(arr, &n, value);
	printf("删除之后的数组：");
	for (i = 0; i < n; ++i)
		printf("%d ", arr[i]);
	printf("\n");
	printf("删除元素的值：%d\n", del_num);
	free(arr); // 释放数组内存
}

void show_max_min_diff()
{ // 3. 自己输入一个整型数组，打印最大值和最小值的差值
	int n;
	printf("请输入数组大小：");
	int n_input = scanf("%d", &n);
	int* arr = create_array(NULL, n);
	int i;
	printf("请输入%d个数组元素(用空格分隔)：\n", n);
	for (i = 0; i < n; ++i)
	{
		int i_input = scanf("%d", &arr[i]);
	}
	int max_num = arr[0];
	int min_num = arr[0];
	for (i = 1; i < n; ++i)
	{
		if (arr[i] > max_num)
			max_num = arr[i];
		if (arr[i] < min_num)
			min_num = arr[i];
	}
	int diff = max_num - min_num;
	printf("最大值：%d\n", max_num);
	printf("最小值：%d\n", min_num);
	printf("最大值和最小值的差值：%d\n", diff);
}

void up_low_reverse()
{ // 将键盘输入的字符数组进行大小写反转，并打印
	//char up_arr[26] = // 大写字符，对应 ASCII 码 65-90
	//{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 
	//  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 
	//  'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
	//char low_arr[26] = // 小写字符，对应 ASCII 码 97-122
	//{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 
	//  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 
	//  's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
	// 可以看到大小学之间差 32，可以利用这个差值进行大小写反转
	/* 此时可以设置 char 类型直接加减，因为 z 对应 ASCII 码 122 小于 127
		不会出现整型提升截断导致结果变化问题 */
	char input;
	printf("请输入字母，输入 0 结束：");
	do
	{
		input = getchar();
		if (input >= 'A' && input <= 'Z')
			//input = low_arr[input - 'A'];
			input = input + 32; // 大小写反转
		//printf("%c ", tolower(input)); // 库函数 tolower() 也可以实现
		else if (input >= 'a' && input <= 'z')
			//input = up_arr[input - 'a'];
			input = input - 32; // 大小写反转
		//printf("%c ", toupper(input)); // 库函数 toupper() 也可以实现
		else if (input == '0')
			break;
		else
		{
			printf("\n请输入字母，输入 0 结束：");
			continue; // 非法输入，跳过
		}
		printf("%c ", input);
		//putchar(input); // 打印反转后的字符
	} while (1);
}

int is_lily_number(int n)
{ // 4. 判断一个 5 位数是否等于其各位数字拆分为两个数之后相乘的和
	if (n < 10000 || n > 99999)
		return -1; // 数位数不是 5 位
	int i, left, right, sum = 0;
	for (i = 10; i < 10001; i *= 10)
	{
		left = n / i; // 取出当前位数
		right = n % i; // 取出余数
		sum += left * right; // 计算当前位数的左右两个数乘积之和
	}
	return sum == n; // 判断，返回 1 或 0
}

void printf_five_lily_number()
{ // 5. 打印 5 位特殊数，即等于其各位数字拆分为两个数之后相乘的和
	int i, count = 0;
	for (i = 10000; i < 100000; ++i)
	{
		if (is_lily_number(i))
		{
			printf("%d ", i);
			++count;
		}
	}
	printf("\n共有 %d 个特殊数。\n", count);
}
